/****************************************************************************
 *   $Id:: uart.c 5751 2010-11-30 23:56:11Z usb00423                        $
 *   Project: NXP LPC17xx UART example
 *
 *   Description:
 *     This file contains UART code example which include UART initialization, 
 *     UART interrupt handler, and APIs for UART access.
 *
 ****************************************************************************
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * products. This software is supplied "AS IS" without any warranties.
 * NXP Semiconductors assumes no responsibility or liability for the
 * use of the software, conveys no license or title under any patent,
 * copyright, or mask work right to the product. NXP Semiconductors
 * reserves the right to make changes in the software without
 * notification. NXP Semiconductors also make no representation or
 * warranty that such application will be suitable for the specified
 * use without further testing or modification.
****************************************************************************/
#include <stdio.h>
#include "LPC17xx.h"
#include "lpc_types.h"
#include "uart.h"

volatile uint32_t uart0_status, uart1_status, uart2_status, uart3_status;
volatile uint8_t uart0_tx_empty = 1, uart1_tx_empty = 1, uart2_tx_empty = 1, uart3_tx_empty = 1;
volatile uint8_t uart0_buffer[BUFSIZE0], uart1_buffer[BUFSIZE1],uart2_buffer[BUFSIZE2],uart3_buffer[BUFSIZE3];
volatile uint32_t uart0_count = 0, uart1_count = 0, uart2_count = 0, uart3_count = 0;

/*****************************************************************************
** Function name:		UART0_IRQHandler
**
** Descriptions:		UART0 interrupt handler
**
** parameters:			None
** Returned value:		None
** 
*****************************************************************************/
void UART0_IRQHandler (void) {
  uint8_t iir_value, lsr_value;
  uint8_t dummy = dummy;
	
  iir_value = LPC_UART0->IIR;
    
  iir_value >>= 1;			/* skip pending bit in IIR */
  iir_value &= 0x07;			/* check bit 1~3, interrupt identification */
  if ( iir_value == IIR_RLS ) {		/* Receive Line Status */
    lsr_value = LPC_UART0->LSR;

    /* Receive Line Status */
    if ( lsr_value & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) ) {
      /* There are errors or break interrupt */
      /* Read LSR will clear the interrupt */
      uart0_status = lsr_value;
      dummy = LPC_UART0->RBR;		/* dummy read on RX to clear
                interrupt, then bail out */
      return;
    }

    if ( lsr_value & LSR_RDR ) {	/* Receive Data Ready */
      /* If no error on RLS, normal ready, save into the data buffer. */
      /* Note: read RBR will clear the interrupt */
      uart0_buffer[uart0_count] = LPC_UART0->RBR;
      uart0_count++;
      if ( uart0_count == BUFSIZE0 )
      {
      uart0_count = 0;		/* buffer overflow */
      }
    }
  }
  else if ( iir_value == IIR_RDA ) {	/* Receive Data Available */
    /* Receive Data Available */
    uart0_buffer[uart0_count] = LPC_UART0->RBR;
    uart0_count++;
    if ( uart0_count == BUFSIZE0 )
    {
      uart0_count = 0;		/* buffer overflow */
    }
  }
  else if ( iir_value == IIR_CTI ) {	/* Character timeout indicator */
    /* Character Time-out indicator */
    uart0_status |= 0x100;		/* Bit 9 as the CTI error */
  }
  else if ( iir_value == IIR_THRE ) {	/* THRE, transmit holding register empty */
    /* THRE interrupt */
    lsr_value = LPC_UART0->LSR;		/* Check status in the LSR to see if
									valid data in U0THR or not */
    if ( lsr_value & LSR_THRE ) {
      uart0_tx_empty = 1;
    }
    else {
      uart0_tx_empty = 0;
    }
  }
}

/*****************************************************************************
** Function name:		UART1_IRQHandler
**
** Descriptions:		UART1 interrupt handler
**
** parameters:			None
** Returned value:		None
** 
*****************************************************************************/
void UART1_IRQHandler (void) 
{
  uint8_t iir_value, lsr_value;
  uint8_t dummy = dummy;
	
  iir_value = LPC_UART1->IIR;
    
  iir_value >>= 1;			/* skip pending bit in IIR */
  iir_value &= 0x07;			/* check bit 1~3, interrupt identification */
  if ( iir_value == IIR_RLS )		/* Receive Line Status */
  {
    lsr_value = LPC_UART1->LSR;
    /* Receive Line Status */
    if ( lsr_value & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) ) {
      /* There are errors or break interrupt */
      /* Read LSR will clear the interrupt */
      uart1_status = lsr_value;
      dummy = LPC_UART1->RBR;		/* dummy read on RX to clear
                  interrupt, then bail out */
      return;
    }
    if ( lsr_value & LSR_RDR )	{ /* Receive Data Ready */
      /* If no error on RLS, normal ready, save into the data buffer. */
      /* Note: read RBR will clear the interrupt */
      uart1_buffer[uart1_count] = LPC_UART1->RBR;
      uart1_count++;
      if ( uart1_count == BUFSIZE1 )
      {
      uart1_count = 0;		/* buffer overflow */
      }
    }
  }
  else if ( iir_value == IIR_RDA ) {	/* Receive Data Available */
    /* Receive Data Available */
    uart1_buffer[uart1_count] = LPC_UART1->RBR;
    uart1_count++;

    if ( uart1_count == BUFSIZE1 ) {
      uart1_count = 0;		/* buffer overflow */
    }
  }
  else if ( iir_value == IIR_CTI ) {	/* Character timeout indicator */
    /* Character Time-out indicator */
    uart1_status |= 0x100;		/* Bit 9 as the CTI error */
  }
  else if ( iir_value == IIR_THRE ) {	/* THRE, transmit holding register empty */
    /* THRE interrupt */
    lsr_value = LPC_UART1->LSR;		/* Check status in the LSR to see if
                  valid data in U0THR or not */
    if ( lsr_value & LSR_THRE ) {
      uart1_tx_empty = 1;
    }
    else {
      uart1_tx_empty = 0;
    }
  }
}

/*****************************************************************************
** Function name:   UART2_IRQHandler
**
** Descriptions:    UART2 interrupt handler
**
** parameters:      None
** Returned value:    None
**
*****************************************************************************/
void UART2_IRQHandler (void)
{
  uint8_t iir_value, lsr_value;
  uint8_t dummy = dummy;

  iir_value = LPC_UART2->IIR;

  iir_value >>= 1;     /* skip pending bit in IIR */
  iir_value &= 0x07;     /* check bit 1~3, interrupt identification */
  if ( iir_value == IIR_RLS )    /* Receive Line Status */
  {
    lsr_value = LPC_UART2->LSR;
    /* Receive Line Status */
    if ( lsr_value & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) ) {
      /* There are errors or break interrupt */
      /* Read LSR will clear the interrupt */
      uart2_status = lsr_value;
      dummy = LPC_UART2->RBR;   /* dummy read on RX to clear
                  interrupt, then bail out */
      return;
    }
    if ( lsr_value & LSR_RDR ) { /* Receive Data Ready */
      /* If no error on RLS, normal ready, save into the data buffer. */
      /* Note: read RBR will clear the interrupt */
      uart2_buffer[uart2_count] = LPC_UART2->RBR;
      uart2_count++;

      if ( uart2_count == BUFSIZE2 )
      {
      uart2_count = 0;   /* buffer overflow */
      }
    }
  }
  else if ( iir_value == IIR_RDA ) { /* Receive Data Available */
    /* Receive Data Available */
    uart2_buffer[uart2_count] = LPC_UART2->RBR;
    uart2_count++;

    if ( uart2_count == BUFSIZE2 ) {
      uart2_count = 0;   /* buffer overflow */
    }
  }
  else if ( iir_value == IIR_CTI ) { /* Character timeout indicator */
    /* Character Time-out indicator */
    uart2_status |= 0x100;   /* Bit 9 as the CTI error */
  }
  else if ( iir_value == IIR_THRE ) {  /* THRE, transmit holding register empty */
    /* THRE interrupt */
    lsr_value = LPC_UART2->LSR;    /* Check status in the LSR to see if
                  valid data in U0THR or not */
    if ( lsr_value & LSR_THRE ) {
      uart2_tx_empty = 1;
    }
    else {
      uart2_tx_empty = 0;
    }
  }

}

/*****************************************************************************
** Function name:   UART3_IRQHandler
**
** Descriptions:    UART3 interrupt handler
**
** parameters:      None
** Returned value:    None
**
*****************************************************************************/
void UART3_IRQHandler (void)
{
  uint8_t iir_value, lsr_value;
  uint8_t dummy = dummy;

  iir_value = LPC_UART3->IIR;

  iir_value >>= 1;     /* skip pending bit in IIR */
  iir_value &= 0x07;     /* check bit 1~3, interrupt identification */

  if ( iir_value == IIR_RLS )    /* Receive Line Status */
  {
    lsr_value = LPC_UART3->LSR;
    /* Receive Line Status */
    if ( lsr_value & (LSR_OE|LSR_PE|LSR_FE|LSR_RXFE|LSR_BI) ) {
      /* There are errors or break interrupt */
      /* Read LSR will clear the interrupt */
      uart3_status = lsr_value;
      dummy = LPC_UART3->RBR;   /* dummy read on RX to clear
                  interrupt, then bail out */
      return;
    }
    if ( lsr_value & LSR_RDR ) { /* Receive Data Ready */
      /* If no error on RLS, normal ready, save into the data buffer. */
      /* Note: read RBR will clear the interrupt */
      uart3_buffer[uart3_count] = LPC_UART3->RBR;
      uart3_count++;
      if ( uart3_count == BUFSIZE3 )
      {
      uart3_count = 0;   /* buffer overflow */
      }
    }
  }
  else if ( iir_value == IIR_RDA ) { /* Receive Data Available */
    /* Receive Data Available */
    uart3_buffer[uart3_count] = LPC_UART3->RBR;
    uart3_count++;

    if ( uart3_count == BUFSIZE3 ) {
      uart3_count = 0;   /* buffer overflow */
    }
  }
  else if ( iir_value == IIR_CTI ) { /* Character timeout indicator */
    /* Character Time-out indicator */
    uart3_status |= 0x100;   /* Bit 9 as the CTI error */
  }
  else if ( iir_value == IIR_THRE ) {  /* THRE, transmit holding register empty */
    /* THRE interrupt */
    lsr_value = LPC_UART3->LSR;    /* Check status in the LSR to see if
                  valid data in U0THR or not */
    if ( lsr_value & LSR_THRE ) {
      uart3_tx_empty = 1;
    }
    else {
      uart3_tx_empty = 0;
    }
  }
}

/*****************************************************************************
** Function name:		UARTInit
**
** Descriptions:		Initialize UART port, setup pin select,
**						clock, parity, stop bits, FIFO, etc.
**
** parameters:			port(0 or 1) and UART baudrate
** Returned value:		true or false, return false only if the 
**						interrupt handler can't be installed to the 
**						VIC table
** 
*****************************************************************************/
uint32_t uart_init( uint32_t port, uint32_t baudrate )
{
  uint32_t f_div;
  uint32_t pclkdiv, pclk;

  if ( port == 0 ) {
    /* By default, the PCLKSELx value is zero, thus, the PCLK for
    all the peripherals is 1/4 of the SystemFrequency. */
    /* Bit 6~7 is for UART0 */
    pclkdiv = (LPC_SC->PCLKSEL0 >> 6) & 0x03;

    switch ( pclkdiv ) {
      case 0x00:
      default:
      pclk = SystemCoreClock/4;
      break;
      case 0x01:
      pclk = SystemCoreClock;
      break;
      case 0x02:
      pclk = SystemCoreClock/2;
      break;
      case 0x03:
      pclk = SystemCoreClock/8;
      break;
    }

    LPC_UART0->LCR = 0x83;		/* 8 bits, no Parity, 1 Stop bit */
    f_div = ( pclk / 16 ) / baudrate ;	/*baud rate */
    LPC_UART0->DLM = f_div / 256;
    LPC_UART0->DLL = f_div % 256;
    LPC_UART0->LCR = 0x03;		/* DLAB = 0 */
    LPC_UART0->FCR = 0x07;		/* Enable and reset TX and RX FIFO. */

   	NVIC_EnableIRQ(UART0_IRQn);

    LPC_UART0->IER = IER_RBR | IER_THRE | IER_RLS;	/* Enable UART0 interrupt */
    return (TRUE);
  }
  else if ( port == 1 ) {
    /* By default, the PCLKSELx value is zero, thus, the PCLK for
    all the peripherals is 1/4 of the SystemFrequency. */
    /* Bit 8,9 are for UART1 */
    pclkdiv = (LPC_SC->PCLKSEL0 >> 8) & 0x03;
    switch ( pclkdiv ) {
      case 0x00:
      default:
      pclk = SystemCoreClock/4;
      break;
      case 0x01:
      pclk = SystemCoreClock;
      break;
      case 0x02:
      pclk = SystemCoreClock/2;
      break;
      case 0x03:
      pclk = SystemCoreClock/8;
      break;
    }

    LPC_UART1->LCR = 0x83;		/* 8 bits, no Parity, 1 Stop bit */
    f_div = ( pclk / 16 ) / baudrate ;	/*baud rate */
    LPC_UART1->DLM = f_div / 256;
    LPC_UART1->DLL = f_div % 256;
    LPC_UART1->LCR = 0x03;		/* DLAB = 0 */
    LPC_UART1->FCR = 0x07;		/* Enable and reset TX and RX FIFO. */

   	NVIC_EnableIRQ(UART1_IRQn);

    LPC_UART1->IER = IER_RBR | IER_THRE | IER_RLS;	/* Enable UART1 interrupt */
    return (TRUE);
  }
  else if ( port == 2 ) {

    /* By default, the PCLKSELx value is zero, thus, the PCLK for
    all the peripherals is 1/4 of the SystemFrequency. */
    /* Bit 8,9 are for UART1 */
    pclkdiv = (LPC_SC->PCLKSEL1 >> 16) & 0x03;
    switch ( pclkdiv ) {
      case 0x00:
      default:
      pclk = SystemCoreClock/4;
      break;
      case 0x01:
      pclk = SystemCoreClock;
      break;
      case 0x02:
      pclk = SystemCoreClock/2;
      break;
      case 0x03:
      pclk = SystemCoreClock/8;
      break;
    }

    LPC_UART2->LCR = 0x83;    /* 8 bits, no Parity, 1 Stop bit */
    f_div = ( pclk / 16 ) / baudrate ; /*baud rate */
    LPC_UART2->DLM = f_div / 256;
    LPC_UART2->DLL = f_div % 256;
    LPC_UART2->LCR = 0x03;    /* DLAB = 0 */
    LPC_UART2->FCR = 0x07;    /* Enable and reset TX and RX FIFO. */

    NVIC_EnableIRQ(UART2_IRQn);

    LPC_UART2->IER = IER_RBR | IER_THRE | IER_RLS;  /* Enable UART2 interrupt */
    return (TRUE);
  }
  else if ( port == 3 ) {
    /* By default, the PCLKSELx value is zero, thus, the PCLK for
    all the peripherals is 1/4 of the SystemFrequency. */
    /* Bit 8,9 are for UART1 */
    pclkdiv = (LPC_SC->PCLKSEL1 >> 18) & 0x03;
    switch ( pclkdiv ) {
      case 0x00:
      default:
      pclk = SystemCoreClock/4;
      break;
      case 0x01:
      pclk = SystemCoreClock;
      break;
      case 0x02:
      pclk = SystemCoreClock/2;
      break;
      case 0x03:
      pclk = SystemCoreClock/8;
      break;
    }

    LPC_UART3->LCR = 0x83;    /* 8 bits, no Parity, 1 Stop bit */
    f_div = ( pclk / 16 ) / baudrate ; /*baud rate */
    LPC_UART3->DLM = f_div / 256;
    LPC_UART3->DLL = f_div % 256;
    LPC_UART3->LCR = 0x03;    /* DLAB = 0 */
    LPC_UART3->FCR = 0x07;    /* Enable and reset TX and RX FIFO. */

    NVIC_EnableIRQ(UART3_IRQn);

    LPC_UART3->IER = IER_RBR | IER_THRE | IER_RLS;  /* Enable UART3 interrupt */
    return (TRUE);
  }

  return( FALSE ); 
}

/*****************************************************************************
** Function name:		uart_send
**
** Descriptions:		Send a block of data to the UART 0 port based
**						on the data length
**
** parameters:			port, buffer pointer, and data length
** Returned value:		None
** 
*****************************************************************************/
void uart_send( uint32_t port, uint8_t *buffer_ptr, uint32_t length ) {
  if ( port == 0 ) {
    while ( length != 0 ) {
      /* THRE status, contain valid data */
      while ( !(uart0_tx_empty & 0x01) );
      LPC_UART0->THR = *buffer_ptr;
      uart0_tx_empty = 0;	/* not empty in the THR until it shifts out */
      buffer_ptr++;
      length--;
    }
  }
  else if (port == 1){
    while ( length != 0 ) {
      /* THRE status, contain valid data */
      while ( !(uart1_tx_empty & 0x01) );

      LPC_UART1->THR = *buffer_ptr;
      uart1_tx_empty = 0;	/* not empty in the THR until it shifts out */
      buffer_ptr++;
      length--;
    }
  }
  else if (port == 2){
    while ( length != 0 ) {
      /* THRE status, contain valid data */
      while ( !(uart2_tx_empty & 0x01) );

      LPC_UART2->THR = *buffer_ptr;
      uart2_tx_empty = 0; /* not empty in the THR until it shifts out */
      buffer_ptr++;
      length--;
    }
  }
  else if (port == 3){
    while ( length != 0 ) {
      /* THRE status, contain valid data */
      while ( !(uart3_tx_empty & 0x01) );

      LPC_UART3->THR = *buffer_ptr;
      uart3_tx_empty = 0; /* not empty in the THR until it shifts out */
      buffer_ptr++;
      length--;
    }
  }

  return;
}

/******************************************************************************
**                            End Of File
******************************************************************************/
